<template>
    <div ref="InputWapRef" class="input-wap" :class="{
        'edit-ready': !disabled && isEditer && editState.status === 'ready',
        'edit-doing': !disabled && isEditer && editState.status === 'doing',
        disabled: disabled
        }"
    >
        <template v-if="disabled || !isEditer || editState.status !== 'doing' ">
            <template v-if="value !== undefined">
                <tooltip :open-tooltip="openTooltip" :auto-tooltip="autoTooltip">{{ $attrs.formatter ?  $attrs.formatter?.(valueText) : valueText }}</tooltip>
            </template>
            <span v-else class="placeholder">{{ placeholder }}</span>
        </template>
        <template v-if="!disabled && isEditer"> 
            <div class="input-controler">
                <slot name="input">
                    <InputNumber v-if="type === 'number'" v-model:value.trim="value" v-bind="$attrs" :formatter="v => v" >
                        <template v-for="(slot, k) in $slots" :key="k" v-slot:[k]="slotProps">
                            <slot :name="k" v-bind="slotProps ?? {}" />
                        </template>
                    </InputNumber>
                    <template v-else>
                        <Teleport :to="TABLE_PARENT" :disabled="!TABLE_PARENT">
                            <Textarea
                                ref="TextareaRef"
                                @compositionstart="compositionstart($event)"
                                @compositionend="compositionend($event)"
                                @mousedown.stop
                                @mouseup.stop
                                auto-size
                                :class="[ noEditing ? 'edit-table-textarea-hide': 'edit-table-textarea', placement]" v-model:value="value"  v-bind="$attrs" 
                                :style="textareaStyle"
                            ></Textarea>
                            <div class="back-computed-width-conetent">
                                <span ref="computedWidthRef" :style="{
                                    'max-width': textareaStyle.maxWidth
                                }">{{ value }} {{ keydownCountCode }}</span>
                            </div>
                        </Teleport>
                    </template>
                </slot>
            </div>
        </template>
        <slot name="suffix"></slot>
    </div>
</template>

<script lang="ts" setup>
import { watch, inject, computed, ref, onMounted, onBeforeUnmount, useAttrs, nextTick } from "vue"
import { Tooltip, InputNumber, Textarea } from "ant-design-vue"
import { EditState, PROVIDE_EDIT_STATE } from "./../plugins/core/type"
import tooltip from "./tooltip.vue"

const props = defineProps({
    isEditer: {
        type: Boolean,
        default: false
    },
    type: {
        type: String,
        default: 'text'
    },
    placeholder: {
        type: String,
        default: undefined
    },
    disabled: {
        type: Boolean,
        default: false
    },
    openTooltip: {
        type: Boolean,
        default: false
    },
    autoTooltip: {
        type: Boolean,
        default: true
    },
})
const emits = defineEmits(["change"])

const value = defineModel('value')

const InputWapRef = ref(null)
const attrs = useAttrs()
const valueText = computed(() => (props.type === 'number' && attrs.formatter) ? attrs.formatter(value.value) : value.value)
const editState: EditState = inject(PROVIDE_EDIT_STATE) as EditState;

watch(value, () => {
    if (props.isEditer && editState.status === 'doing') emits("change", value.value)
})

// 是否处在未编辑状态
const noEditing = computed(() => {
    return !(!props.disabled && props.isEditer && editState.status === 'doing')
})
// 传送的节点
const CURRENT_TD = ref<HTMLElement>()
const selectTd = () => {
    if (CURRENT_TD.value) return;
    // console.log(888)
    let td: any = InputWapRef.value;
    while(td.tagName !== 'TD') td = td.parentElement;
    CURRENT_TD.value = td
}
const TABLE = ref<HTMLElement>()
// table元素的父级
const TABLE_PARENT = ref<HTMLElement>()
const selecTableParent = () => {
    if (TABLE_PARENT.value || !CURRENT_TD.value) return;
    // console.log(999)
    let node: any = CURRENT_TD.value;
    while(node.tagName !== 'TABLE') node = node.parentElement;
    TABLE.value = node
    TABLE_PARENT.value = node.parentElement
}



const placement = ref<'top' | 'bottom'>('bottom');
const textareaStyle = ref<any>({})
const computedWidthRef = ref()

let absoverConentChange: any;
const createObsover = () => {
    if (absoverConentChange || !computedWidthRef.value) return;
    absoverConentChange = new ResizeObserver((entries, observer) => {
        for (const entry of entries) {
            const { contentRect } = entry;
            textareaStyle.value.width = computedWidthRef.value.offsetWidth + 24 + 'px'
            textareaStyle.value.minHeight = Math.max(25, computedWidthRef.value.offsetHeight) + 'px !important'
        }
    });
    absoverConentChange?.observe?.(computedWidthRef.value)
}
const cancelObsover = () => { 
    absoverConentChange?.unobserve?.(computedWidthRef.value)
    absoverConentChange?.disconnect?.()
    absoverConentChange = null;
}

// cancel listen scroll
const cancelListenScrollHandel = () => {
    const scrollbox = TABLE_PARENT.value?.parentElement
    scrollbox?.removeEventListener?.('scroll', listenScrollHandel)
}
// listen scroll
const listenScrollHandel = () => {
    if(editState.status === 'doing') editState.status = 'ready'
    cancelListenScrollHandel()
}

const TextareaRef = ref()
let keydownCountCode = ref("");
const compositionstart = () => {
    keydownCountCode.value = '';
    TextareaRef.value?.$el?.addEventListener("compositionupdate", compositionupdate)
}
const compositionend = () => {
    keydownCountCode.value = '';
    TextareaRef.value?.$el?.removeEventListener("compositionupdate", compositionupdate)
}
const compositionupdate = (e: any) => {
    keydownCountCode.value = e.data
}

const computedTextareaStyle = () => {
    if (!TABLE_PARENT.value || !CURRENT_TD.value || !TABLE.value) {
        throw '表格节点未找到.'
    };

    const scrollbox: HTMLElement = TABLE_PARENT.value.parentElement as HTMLElement

    const offsetTop = (CURRENT_TD.value?.offsetTop ?? 0) - scrollbox.scrollTop;
    const offsetLeft = Math.max((CURRENT_TD.value?.offsetLeft ?? 0) - scrollbox.scrollLeft, 0);
    const offsetBottom = scrollbox.offsetHeight - offsetTop - CURRENT_TD.value.offsetHeight;

    placement.value = offsetTop * 2 > scrollbox.clientHeight ? 'top' : 'bottom'

    textareaStyle.value = {
        width: 0,
        maxWidth: TABLE_PARENT.value.offsetWidth - offsetLeft + 'px',
        minWidth: CURRENT_TD.value.offsetWidth + 1 + 'px',
        maxHeight: (placement.value === 'top' ? offsetTop : offsetBottom) + 'px',
        left: offsetLeft - 1 + 'px',
        [placement.value === 'bottom' ? 'top' : 'bottom']: (placement.value === 'top' ? offsetBottom + 1 : offsetTop) - 1 + 'px',
    }
}

onMounted(() => {
    if (props.type !== 'number') {

        watch(() => !props.disabled && props.isEditer, val => {
            if (val) {
                selectTd()
                selecTableParent() 
                computedTextareaStyle()
            }
        })
        
        watch(noEditing, (dt) => {
            if (dt) {
                cancelObsover()
                cancelListenScrollHandel()
            } else {
                computedTextareaStyle()
                const scrollbox: HTMLElement = TABLE_PARENT.value?.parentElement as HTMLElement;
                // listen content size
                createObsover()
                scrollbox.addEventListener('scroll', listenScrollHandel)
            } 
        })
    }
})

onBeforeUnmount(() => {
    cancelObsover()
    cancelListenScrollHandel()
    CURRENT_TD.value = undefined;
    TABLE_PARENT.value = undefined;
})

</script>

<style scoped lang="less">
.input-wap{
    display: flex;
    width: 100%;
    height: 23px;
    line-height: 20px;
    align-items: center;
    justify-content: space-between;
    .placeholder,
    .overflow-text{
        flex: 1;
    }
    .input-controler{
        flex: 1;
        height: inherit;
        .ant-input-number-input{
            border-radius: none !important;
            /* font-size: calc(1em + 1px); */
        }
    }
    &.edit-ready{
        .input-controler,
        .input-controler input{
            width: 0;
            flex: unset;
            overflow: hidden;
        }
    }
    &.edit-doing{
        .placeholder,
        :deep(.overflow-text),
        .overflow-text{
            display: none !important;
            flex: unset;
        }
        :deep(.ant-input-number-input){
            position: absolute;
        }
    }
}
.disabled{
    cursor: not-allowed;
}
</style>

<style lang="less">
@td-chosed-bgcolor: #deeeff;
@td-chosed-bordercolor: rgba(0, 127, 255, 0.5);
.table-pannel{
    textarea.ant-input{
        opacity: 0;
    }
}
.edit-table-textarea{
    background-color: @td-chosed-bgcolor !important;
    z-index: 20 !important;
    border-color: @td-chosed-bordercolor !important;
    border-radius: 0 !important;
    padding: 0 1px !important;
    min-height: 0 !important;
    position: absolute !important;
    min-height: 25px !important;
    user-select: none !important;
    transition: opacity 50ms !important;
    display: inline-block !important;
    opacity: 1 !important;
    height: 0;
    line-height: 1.5 !important;
    font-size: 12px !important;
    outline: none !important;
    box-shadow: none !important;
    padding-top: 3px !important;
    // left: -1px;
    // right: -1px;
    // max-width: unset !important;
    // width: auto !important;
    // line-height: 24px !important;
    // &.top{
    //     bottom: -1px;
    // }
    // &.bottom{
    //     top: -1px;
    // }
}
.edit-table-textarea-hide{
    width: 0 !important;
    height: 0 !important;
    overflow: hidden !important;
    min-height: 0px !important;
    position: absolute !important;
    padding: 0 !important;
    opacity: 0 !important;
    transition: none !important;
    border: 0 !important;
}
.back-computed-width-conetent{
    // width: 0;
    height: 0;
    opacity: 0;
    overflow: hidden;
    font-size: 12px;
    line-height: 1.65;
    span{
        display: inline-block;
    }
}
</style>
